/*
	Copyright 2008 Jay Elliott

	This file is part of libemath.

	libemath is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	libemath is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with libemath.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __CPLANE_H_
#define __CPLANE_H_

#include <cstdio>
#include <cmath>

#include "cPoint3d.h"
#include "macros.h"

namespace emath
{

class cPlane
{
public:
	enum CLASSIFICATION
	{
		COINCIDES = 0,//point is on plane
		IN_FRONT = 1,//point is in front of plane
		BEHIND = -1//point is behind plane
	};
private:
	cPoint3d norm;
	float dist;

public:
	inline cPlane() {}
	inline cPlane(const cPoint3d points[3]);
	inline cPlane(const cPoint3d& p1, const cPoint3d& p2, const cPoint3d& p3);
	inline cPlane(const cPoint3d& normal, float d);

	inline cPoint3d GetNorm(void) const;
	inline float GetDist(void) const;

	inline float DistanceTo(const cPoint3d& point) const;

	inline CLASSIFICATION classify(const cPoint3d& point) const;
};



/*************************************
*
*
*	inline function definitions
*
*
***************************************/



cPlane::cPlane(const cPoint3d points[3])
{
	cPoint3d vec1(points[1] - points[0]);
	cPoint3d vec2(points[2] - points[1]);

	norm = vec1.cross(vec2).normalize();
	dist = -norm.dot(points[0]);
}

cPlane::cPlane(const cPoint3d& p1, const cPoint3d& p2, const cPoint3d& p3)
{
	cPoint3d vec1(p2 - p1);
	cPoint3d vec2(p3 - p2);

	norm = vec1.cross(vec2).normalize();
	dist = -norm.dot(p1);
}

cPlane::cPlane(const cPoint3d& normal, float d)
{
	norm = normal.normalize();
	dist = d;
}

cPlane::CLASSIFICATION cPlane::classify(const cPoint3d& point) const
{
	float distance = norm.dot(point) + dist;


	if (distance < -EPSILON)
		return BEHIND;

	if (distance > EPSILON)
		return IN_FRONT;

	return COINCIDES;
}

cPoint3d cPlane::GetNorm(void) const
{
	return norm;
}

float cPlane::GetDist(void) const
{
	return dist;
}

float cPlane::DistanceTo(const emath::cPoint3d& point) const
{
	return norm.dot(point) + dist;
}

}
#endif
